/*
Copyright 2011, 2012 Alessandro Magnolo.

This file is part of Backlight Indicator.

Backlight Indicator is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Backlight Indicator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Backlight Indicator.  If not, see <http://www.gnu.org/licenses/>.
*/
package com.magnolo.backlight_indicator;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.Scanner;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.util.Log;

public class BacklightIndicator {
	private static final String LOG_TAG="BacklightIndicator";
	/**
	 * Pixel Qi status file.
	 */
	private static final String STATUS_FILE_PQI="/sys/devices/platform/pixel_qi_screen_ctrl/state";
	/**
	 * ICS Pixel Qi status file.
	 */
	private static final String STATUS_FILE_ICS_PQI="/sys/class/backlight/pwm-backlight/device/PQiModeOn";
	/**
	 * Dummy file to use in the emulator to simulate the Pixel Qi status file.
	 */
	private static final String STATUS_FILE_EMULATOR="/sdcard/pixel_qi_screen_ctrl/state";
	private static final int BACKLIGHT_ON=1;
	private static final int BACKLIGHT_OFF=0;
	static final String PREFERENCE_SHARED_NAME="sharedPreferences";
	static final String PREFERENCE_MODE="operatingMode";
	static final int STATUS_NOTIFICATION_ID=1;

	/**
	 * Switches the backlight on or off, and stores the new status in the preferences. If the status
	 * is unknown, it sets the mode to UPDATE_ICON.
	 * 
	 * @param status
	 *           to set the backlight to
	 * @return true if this invocation changed the previous state
	 */
	static boolean setStatusAndStorePref(BacklightStatus newStatus, Context context) {
		// Store values between instances here
		//SharedPreferences preferences=getPreferences(MODE_PRIVATE);
		OperatingMode newMode;
		if (newStatus==BacklightStatus.ON) newMode=OperatingMode.FORCE_ON;
		else if (newStatus==BacklightStatus.OFF) newMode=OperatingMode.FORCE_OFF;
		else newMode=OperatingMode.UPDATE_ICON;

		SharedPreferences preferences=context.getSharedPreferences(PREFERENCE_SHARED_NAME, Context.MODE_PRIVATE);
		SharedPreferences.Editor editor=preferences.edit();
		editor.putString(BacklightIndicator.PREFERENCE_MODE, newMode.toString());
		editor.commit();

		boolean wasSet=BacklightIndicator.setStatus(newStatus);
		//if (wasSet) updateIndicator(context, "setStatus");
		updateIndicator(context, "setStatus"); // I have to do the update even if !wasSet, in case the mode is update_icon
		return wasSet;
	}

	/**
	 * Switches the backlight on or off.
	 * 
	 * @param status
	 *           to set the backlight to
	 * @return true if this invocation changed the previous state
	 */
	private static boolean setStatus(BacklightStatus newStatus) {
		BacklightStatus oldStatus=BacklightIndicator.checkStatus();
		Log.d(LOG_TAG, "old="+oldStatus+" new="+newStatus);
		if (oldStatus!=newStatus&&newStatus!=BacklightStatus.UNKNOWN) {
			if (isIcsPqi()) {
				// ICS swapped constants values!
				String[] cmda = { "/system/bin/sh", "-c", "echo "+(newStatus==BacklightStatus.OFF ? BACKLIGHT_ON : BACKLIGHT_OFF)+" > "+STATUS_FILE_ICS_PQI, };
				try {				
					Runtime.getRuntime().exec(cmda);
				} catch (IOException e) {
					Log.w(LOG_TAG, "couldn't update status: "+e); // TODO: notify user
				}
			} else {
				File statusFile=new File(BacklightIndicator.isPqi() ? STATUS_FILE_PQI : STATUS_FILE_EMULATOR);
				/*OutputStream os=new FileOutputStream(statusFile);
				if (newStatus==BacklightStatus.ON) os.write(BACKLIGHT_ON);
				else if (newStatus==BacklightStatus.OFF) os.write(BACKLIGHT_OFF);
				else Log.w(LOG_TAG, "can't set status "+newStatus);
				 */
				String cmd="echo "+(newStatus==BacklightStatus.OFF ? BACKLIGHT_OFF : BACKLIGHT_ON)+" > "+statusFile;
				/*if (Root.execute(cmd)) updateDisplayStatus();
				else Log.w(LOG_TAG, "couldn't update status"); // TODO: notify user*/
				/*} catch (FileNotFoundException e) {
					Log.e(LOG_TAG, "status file not found or not writable "+e);
				} catch (IOException e) {
					Log.e(LOG_TAG, "error writing status file "+e);*/
				if (Root.execute(cmd)) return true;
				else Log.w(LOG_TAG, "couldn't update status"); // TODO: notify user
			}
		}
		return false;
	}

	/**
	 * Checks if the screen is Pixel QI.
	 * 
	 * @return true if the screen is Pixel QI, false otherwise
	 */
	static boolean isPqi() {
		return new File(STATUS_FILE_PQI).exists();
	}
	
	/**
	 * Checks if the screen is ICS Pixel QI.
	 * 
	 * @return true if the screen is ICS Pixel QI, false otherwise
	 */
	static boolean isIcsPqi() {
		return new File(STATUS_FILE_ICS_PQI).exists();
	}

	/**
	 * Checks if the backlight is currently on or off.
	 * 
	 * @return the current backlight status
	 */
	static BacklightStatus checkStatus() {
		BacklightStatus status;
		File statusFile=new File(isPqi() ? STATUS_FILE_PQI : STATUS_FILE_EMULATOR);
		if (isIcsPqi()) statusFile=new File(STATUS_FILE_ICS_PQI);

		Scanner scan=null;
		try {
			scan=new Scanner(statusFile);
		} catch (FileNotFoundException e) {
			Log.e(LOG_TAG, "status file not found "+e);
			return BacklightStatus.UNKNOWN;
		}

		int intStatus=scan.nextInt();
		//Log.d(LOG_TAG, "int status = "+intStatus);
		switch (intStatus) {
		case BACKLIGHT_OFF:
			status=BacklightStatus.OFF;
			if (isIcsPqi()) status=BacklightStatus.ON; // ICS swapped constants values! 
			break;

		case BACKLIGHT_ON:
			status=BacklightStatus.ON;
			if (isIcsPqi()) status=BacklightStatus.OFF; // ICS swapped constants values!
			break;

		default:
			status=BacklightStatus.UNKNOWN;
			break;
		}
		return status;
	}

	private static void notifyStatusBar(Context context, String cause) {
		Log.d(LOG_TAG, "notify status bar: "+cause);
		BacklightStatus currentStatus=checkStatus();

		NotificationManager mNotificationManager=(NotificationManager) context
		   .getSystemService(Context.NOTIFICATION_SERVICE);

		// Instantiate the Notification:
		int icon=BacklightStatus.ON==currentStatus ? R.drawable.ic_stat_on : R.drawable.ic_stat_off;
		//CharSequence tickerText = "Backlight "+status;
		CharSequence tickerText=cause.lastIndexOf(".")>0 ? cause.substring(cause.lastIndexOf(".")) : cause/*+" "
		                                                                                                  +new Date().getSeconds()*/;
		long when=System.currentTimeMillis();

		tickerText=null; // if tickertext is null, no popup is shown in status bar, just the icon
		Notification notification=new Notification(icon, tickerText, when);

		// Define the notification's message and PendingIntent:
		CharSequence contentTitle="Backlight is "+currentStatus;
		//CharSequence contentText=cause/*+" "+new Date().getSeconds()*/;

		/*CharSequence contentText="Backlight Indicator "+version;
		 String version;
		try {
			version=context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName;
		} catch (NameNotFoundException e) {
			version=e.toString();
		}
		 */
		
		SharedPreferences preferences=context.getSharedPreferences(BacklightIndicator.PREFERENCE_SHARED_NAME,
		   Context.MODE_PRIVATE);
		String prefModeString=preferences.getString(BacklightIndicator.PREFERENCE_MODE,
		   OperatingMode.UPDATE_ICON.toString());
		OperatingMode prefMode=OperatingMode.valueOf(prefModeString);
		CharSequence contentText="Mode: "+prefMode.toDescription(context);

		Intent notificationIntent=new Intent(context, Backlight_indicatorActivity.class);
		PendingIntent contentIntent=PendingIntent.getActivity(context, 0, notificationIntent, 0);
		notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);

		// Pass the Notification to the NotificationManager:
		mNotificationManager.notify(STATUS_NOTIFICATION_ID, notification);
	}

	/*
	private void notifyStatusBar(BacklightStatus status) {
		NotificationManager mNotificationManager=(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

		// Instantiate the Notification:

		int icon=BacklightStatus.ON==status ? R.drawable.bulb_on : R.drawable.bulb_off;
		CharSequence tickerText="Backlight status ticker";
		long when=System.currentTimeMillis();

		Notification notification=new Notification(icon, tickerText, when);

		// Define the notification's message and PendingIntent:
		Context context=getApplicationContext();
		CharSequence contentTitle="My notification - content title";
		CharSequence contentText="Hello World! - content text";
		Intent notificationIntent=new Intent(this, class);
		PendingIntent contentIntent=PendingIntent.getActivity(this, 0, notificationIntent, 0);

		notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);

		// Pass the Notification to the NotificationManager:
		final int STATUS_NOTIFICATION_ID=1;
		mNotificationManager.notify(STATUS_NOTIFICATION_ID, notification);
	}*/

	static void updateIndicator(Context context, String cause) {
		//SharedPreferences preferences=getPreferences(MODE_PRIVATE);
		SharedPreferences preferences=context.getSharedPreferences(PREFERENCE_SHARED_NAME,
		   Backlight_indicatorActivity.MODE_PRIVATE);
		String prefModeString=preferences.getString(PREFERENCE_MODE, OperatingMode.UPDATE_ICON.toString());
		OperatingMode prefMode=OperatingMode.valueOf(prefModeString);

		if (prefMode==OperatingMode.FORCE_ON) setStatus(BacklightStatus.ON);
		else if (prefMode==OperatingMode.FORCE_OFF) setStatus(BacklightStatus.OFF);

		notifyStatusBar(context, cause);
		/*SharedPreferences preferences=getPreferences(Activity.MODE_PRIVATE);
		new Backlight_indicatorActivity().notifyStatusBar(context, preferences, intent.getAction());*/
	}

	/**
	 * Toggles the backlight.
	 * 
	 * @param context
	 */
	public static void toggleStatus(Context context) {
		BacklightStatus currentStatus=checkStatus();
		switch (currentStatus) {
		case ON:
			setStatusAndStorePref(BacklightStatus.OFF, context);
			break;

		case OFF:
			setStatusAndStorePref(BacklightStatus.ON, context);
			break;

		default:
			// noop
			break;
		}

	}

}
